#include <stdint.h>
#include <string.h>
#include <lua.h>
#include <lauxlib.h>

#define DEFINE_INT_FUNC(Type, LuaType)                                                  \
	static int lua_read_##Type(lua_State* L)                                            \
	{                                                                                   \
		size_t buf_size;                                                                \
		const char* buf = luaL_checklstring(L, 1, &buf_size);                           \
		size_t offset = luaL_checkinteger(L, 2);                                        \
		size_t type_size = sizeof(Type##_t);                                            \
                                                                                        \
		if (offset + type_size > buf_size) {                                            \
			luaL_error(L, "Offset %zu out of range (buffer size: %zu, type size: %zu)", \
				offset, buf_size, type_size);                                           \
		}                                                                               \
                                                                                        \
		Type##_t val = 0;                                                               \
		memcpy(&val, buf + offset, type_size);                                          \
		lua_push##LuaType(L, val);                                                      \
		return 1;                                                                       \
	}                                                                                   \
	static int lua_write_##Type(lua_State* L)                                           \
	{                                                                                   \
		Type##_t val = lua_tointeger(L, 1);                                             \
		lua_pushlstring(L, (const char*)&val, sizeof(val));                             \
		return 1;                                                                       \
	}

// 为每种类型生成函数
DEFINE_INT_FUNC(int8, integer)
DEFINE_INT_FUNC(int16, integer)
DEFINE_INT_FUNC(int32, integer)
DEFINE_INT_FUNC(int64, integer)
DEFINE_INT_FUNC(uint8, integer)
DEFINE_INT_FUNC(uint16, integer)
DEFINE_INT_FUNC(uint32, integer)
DEFINE_INT_FUNC(uint64, integer)

static int bit32_lshift(lua_State* L)
{
	uint32_t i = lua_tointeger(L, 1);
	uint32_t shift = lua_tointeger(L, 2);
	lua_pushinteger(L, i << shift);
	return 1;
}

static int bit32_rshift(lua_State* L)
{
	uint32_t i = lua_tointeger(L, 1);
	uint32_t shift = lua_tointeger(L, 2);
	lua_pushinteger(L, i >> shift);
	return 1;
}

static int bit32_band(lua_State* L)
{
	int top = lua_gettop(L);
	int i;
	if (top < 1)
		return 0;
	uint32_t a = lua_tointeger(L, 1);
	for (i = 2; i <= top; i++) {
		uint32_t b = lua_tointeger(L, i);
		a &= b;
	}
	lua_pushinteger(L, a);
	return 1;
}

static int bit32_bor(lua_State* L)
{
	int top = lua_gettop(L);
	int i;
	if (top < 1)
		return 0;
	uint32_t a = lua_tointeger(L, 1);
	for (i = 2; i <= top; i++) {
		uint32_t b = lua_tointeger(L, i);
		a |= b;
	}
	lua_pushinteger(L, a);
	return 1;
}

static int bit32_bnot(lua_State* L)
{
	uint32_t a = lua_tointeger(L, 1);
	a = ~a;
	lua_pushinteger(L, a);
	return 1;
}

static int bit32_bxor(lua_State* L)
{
	int top = lua_gettop(L);
	int i;
	if (top < 1)
		return 0;
	uint32_t a = lua_tointeger(L, 1);
	for (i = 2; i <= top; i++) {
		uint32_t b = lua_tointeger(L, i);
		a ^= b;
	}
	lua_pushinteger(L, a);
	return 1;
}

static int luagame_bit32(lua_State* L)
{
	lua_newtable(L);

#define reg_intfunc(n)               \
	lua_pushliteral(L, #n);          \
	lua_pushcfunction(L, bit32_##n); \
	lua_rawset(L, -3)

	reg_intfunc(band);
	reg_intfunc(bor);
	reg_intfunc(bnot);
	reg_intfunc(bxor);
	reg_intfunc(lshift);
	reg_intfunc(rshift);

#undef reg_intfunc
	return 1;
}

LUA_API int luaopen_luagame(lua_State* L)
{
	lua_newtable(L);

#define regfunc(n)                 \
	lua_pushliteral(L, #n);        \
	lua_pushcfunction(L, lua_##n); \
	lua_rawset(L, -3)

#define reg_intfunc(n) \
	regfunc(read_##n); \
	regfunc(write_##n)

	reg_intfunc(int8);
	reg_intfunc(int16);
	reg_intfunc(int32);
	reg_intfunc(int64);
	reg_intfunc(uint8);
	reg_intfunc(uint16);
	reg_intfunc(uint32);
	reg_intfunc(uint64);

	lua_pushliteral(L, "bit32");
	luagame_bit32(L);
	lua_rawset(L, -3);

	return 1;
}
